home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / Direct3D / MultiAnimation / AllocHierarchy.cpp next >
Encoding:
C/C++ Source or Header  |  2004-09-27  |  13.7 KB  |  423 lines

  1. //-----------------------------------------------------------------------------
  2. // File: AllocHierarchy.cpp
  3. //
  4. // Desc: Implementation of the CMultiAnimAllocateHierarchy class, which
  5. //       handles creating and destroying animation frames and mesh containers
  6. //       for the CMultiAnimation library.
  7. //
  8. // Copyright (c) Microsoft Corporation. All rights reserved
  9. //-----------------------------------------------------------------------------
  10.  
  11.  
  12. #include "dxstdafx.h"
  13. #include "MultiAnimation.h"
  14.  
  15.  
  16.  
  17.  
  18. //-----------------------------------------------------------------------------
  19. // Name: HeapCopy()
  20. // Desc: Allocate buffer in memory and copy the content of sName to the
  21. //       buffer, then return the address of the buffer.
  22. //-----------------------------------------------------------------------------
  23. CHAR *HeapCopy( CHAR *sName )
  24. {
  25.     DWORD dwLen = (DWORD) strlen( sName );
  26.     CHAR * sNewName = new CHAR[ dwLen + 1 ];
  27.     strncpy( sNewName, sName, dwLen );
  28.     sNewName[ dwLen ] = '\0';
  29.     return sNewName;
  30. }
  31.  
  32.  
  33.  
  34.  
  35. //-----------------------------------------------------------------------------
  36. // Name: CMultiAnimAllocateHierarchy::CMultiAnimAllocateHierarchy()
  37. // Desc: Constructor of CMultiAnimAllocateHierarchy
  38. //-----------------------------------------------------------------------------
  39. CMultiAnimAllocateHierarchy::CMultiAnimAllocateHierarchy() :
  40.     m_pMA( NULL )
  41. {
  42. }
  43.  
  44.  
  45.  
  46.  
  47. //-----------------------------------------------------------------------------
  48. // Name: CMultiAnimAllocateHierarchy::SetMA()
  49. // Desc: Sets the member CMultiAnimation pointer.  This is the CMultiAnimation
  50. //       we work with during the callbacks from D3DX.
  51. //-----------------------------------------------------------------------------
  52. HRESULT CMultiAnimAllocateHierarchy::SetMA( THIS_ CMultiAnim *pMA )
  53. {
  54.     m_pMA = pMA;
  55.  
  56.     return S_OK;
  57. }
  58.  
  59.  
  60.  
  61.  
  62. //-----------------------------------------------------------------------------
  63. // Name: CMultiAnimAllocateHierarchy::CreateFrame()
  64. // Desc: Called by D3DX during the loading of a mesh hierarchy.  The app can
  65. //       customize its behavior.  At a minimum, the app should allocate a
  66. //       D3DXFRAME or a child of it and fill in the Name member.
  67. //-----------------------------------------------------------------------------
  68. HRESULT CMultiAnimAllocateHierarchy::CreateFrame( THIS_ LPCSTR Name, LPD3DXFRAME * ppFrame )
  69. {
  70.     assert( m_pMA );
  71.  
  72.     * ppFrame = NULL;
  73.  
  74.     MultiAnimFrame * pFrame = new MultiAnimFrame;
  75.     if( pFrame == NULL )
  76.     {
  77.         DestroyFrame( pFrame );
  78.         return E_OUTOFMEMORY;
  79.     }
  80.  
  81.     ZeroMemory( pFrame, sizeof( MultiAnimFrame ) );
  82.  
  83.     if( Name )
  84.         pFrame->Name = (CHAR *) HeapCopy( (CHAR *) Name );
  85.     else
  86.     {
  87.         // TODO: Add a counter to append to the string below
  88.         //       so that we are using a different name for
  89.         //       each bone.
  90.         pFrame->Name = (CHAR *) HeapCopy( "<no_name>" );
  91.     }
  92.  
  93.     if( pFrame->Name == NULL )
  94.     {
  95.         DestroyFrame( pFrame );
  96.         return E_OUTOFMEMORY;
  97.     }
  98.  
  99.     * ppFrame = pFrame;
  100.     return S_OK;
  101. }
  102.  
  103.  
  104.  
  105.  
  106. //-----------------------------------------------------------------------------
  107. // Name: CMultiAnimAllocateHierarchy::CreateMeshContainer()
  108. // Desc: Called by D3DX during the loading of a mesh hierarchy. At a minumum,
  109. //       the app should allocate a D3DXMESHCONTAINER or a child of it and fill
  110. //       in the members based on the parameters here.  The app can further
  111. //       customize the allocation behavior here.  In our case, we initialize
  112. //       m_amxBoneOffsets from the skin info for convenience reason.
  113. //       Then we call ConvertToIndexedBlendedMesh to obtain a new mesh object
  114. //       that's compatible with the palette size we have to work with.
  115. //-----------------------------------------------------------------------------
  116. HRESULT CMultiAnimAllocateHierarchy::CreateMeshContainer( THIS_
  117.     LPCSTR Name,
  118.     CONST D3DXMESHDATA *pMeshData,
  119.     CONST D3DXMATERIAL *pMaterials,
  120.     CONST D3DXEFFECTINSTANCE *pEffectInstances,
  121.     DWORD NumMaterials,
  122.     CONST DWORD *pAdjacency,
  123.     LPD3DXSKININFO pSkinInfo, 
  124.     LPD3DXMESHCONTAINER *ppNewMeshContainer )
  125. {
  126.     assert( m_pMA );
  127.  
  128.     * ppNewMeshContainer = NULL;
  129.  
  130.     HRESULT hr = S_OK;
  131.  
  132.     MultiAnimMC * pMC = new MultiAnimMC;
  133.     if( pMC == NULL )
  134.     { hr = E_OUTOFMEMORY; goto e_Exit; }
  135.  
  136.     ZeroMemory( pMC, sizeof( MultiAnimMC ) );
  137.  
  138.     // if this is a static mesh, exit early; we're only interested in skinned meshes
  139.     if( pSkinInfo == NULL )
  140.     {
  141.         hr = S_OK;
  142.         goto e_Exit;
  143.     }
  144.  
  145.     // only support mesh type
  146.     if( pMeshData->Type != D3DXMESHTYPE_MESH )
  147.     { hr = E_FAIL; goto e_Exit; }
  148.  
  149.     if( Name )
  150.         pMC->Name = (CHAR *) HeapCopy( (CHAR *) Name );
  151.     else
  152.         pMC->Name = (CHAR *) HeapCopy( "<no_name>" );
  153.  
  154.     // copy the mesh over
  155.     pMC->MeshData.Type = pMeshData->Type;
  156.     pMC->MeshData.pMesh = pMeshData->pMesh;
  157.     pMC->MeshData.pMesh->AddRef();
  158.  
  159.     // copy adjacency over
  160.     {
  161.         DWORD dwNumFaces = pMC->MeshData.pMesh->GetNumFaces();
  162.         pMC->pAdjacency = new DWORD[ 3 * dwNumFaces ];
  163.         if( pMC->pAdjacency == NULL )
  164.         { hr = E_OUTOFMEMORY; goto e_Exit; }
  165.  
  166.         CopyMemory( pMC->pAdjacency, pAdjacency, 3 * sizeof( DWORD ) * dwNumFaces );
  167.     }
  168.  
  169.     // ignore effects instances
  170.     pMC->pEffects = NULL;
  171.  
  172.     // alloc and copy materials
  173.     pMC->NumMaterials = max( 1, NumMaterials );
  174.     pMC->pMaterials = new D3DXMATERIAL           [ pMC->NumMaterials ];
  175.     pMC->m_apTextures = new LPDIRECT3DTEXTURE9   [ pMC->NumMaterials ];
  176.     if( pMC->pMaterials == NULL || pMC->m_apTextures == NULL )
  177.     { hr = E_OUTOFMEMORY; goto e_Exit; }
  178.  
  179.     if( NumMaterials > 0 )
  180.     {
  181.         CopyMemory( pMC->pMaterials, pMaterials, NumMaterials * sizeof( D3DXMATERIAL ) );
  182.         for( DWORD i = 0; i < NumMaterials; ++ i )
  183.         {
  184.             if( pMC->pMaterials[ i ].pTextureFilename )
  185.             {
  186.                 // CALLBACK to get valid filename
  187.                 WCHAR sNewPath[ MAX_PATH ];
  188.                 WCHAR wszTexName[ MAX_PATH ];
  189.                 if( MultiByteToWideChar( CP_ACP, 0, pMC->pMaterials[ i ].pTextureFilename, -1, wszTexName, MAX_PATH ) == 0 )
  190.                     pMC->m_apTextures[ i ] = NULL;
  191.                 else
  192.                     if( SUCCEEDED( DXUTFindDXSDKMediaFileCch( sNewPath, MAX_PATH, wszTexName ) ) )
  193.                     {
  194.                         // create the D3D texture
  195.                         if( FAILED( D3DXCreateTextureFromFile( m_pMA->m_pDevice,
  196.                             sNewPath,
  197.                             &pMC->m_apTextures[ i ] ) ) )
  198.                             pMC->m_apTextures[ i ] = NULL;
  199.                     }
  200.                     else
  201.                         pMC->m_apTextures[ i ] = NULL;
  202.             }
  203.             else
  204.                 pMC->m_apTextures[ i ] = NULL;
  205.         }
  206.     }
  207.     else    // mock up a default material and set it
  208.     {
  209.         ZeroMemory( & pMC->pMaterials[ 0 ].MatD3D, sizeof( D3DMATERIAL9 ) );
  210.         pMC->pMaterials[ 0 ].MatD3D.Diffuse.r = 0.5f;
  211.         pMC->pMaterials[ 0 ].MatD3D.Diffuse.g = 0.5f;
  212.         pMC->pMaterials[ 0 ].MatD3D.Diffuse.b = 0.5f;
  213.         pMC->pMaterials[ 0 ].MatD3D.Specular = pMC->pMaterials[ 0 ].MatD3D.Diffuse;
  214.         pMC->pMaterials[ 0 ].pTextureFilename = NULL;
  215.     }
  216.  
  217.     // save the skininfo object
  218.     pMC->pSkinInfo = pSkinInfo;
  219.     pSkinInfo->AddRef();
  220.  
  221.     // Get the bone offset matrices from the skin info
  222.     pMC->m_amxBoneOffsets = new D3DXMATRIX[ pSkinInfo->GetNumBones() ];
  223.     if( pMC->m_amxBoneOffsets == NULL )
  224.     { hr = E_OUTOFMEMORY; goto e_Exit; }
  225.     {
  226.         for( DWORD i = 0; i < pSkinInfo->GetNumBones(); ++ i )
  227.             pMC->m_amxBoneOffsets[ i ] = * (D3DXMATRIX *) pSkinInfo->GetBoneOffsetMatrix( i );
  228.     }
  229.  
  230.     //
  231.     // Determine the palette size we need to work with, then call ConvertToIndexedBlendedMesh
  232.     // to set up a new mesh that is compatible with the palette size.
  233.     //
  234.     {
  235.         UINT iPaletteSize = 0;
  236.         m_pMA->m_pEffect->GetInt( "MATRIX_PALETTE_SIZE", (INT *) & iPaletteSize );
  237.         pMC->m_dwNumPaletteEntries = min( iPaletteSize, pMC->pSkinInfo->GetNumBones() );
  238.     }
  239.  
  240.     // generate the skinned mesh - creates a mesh with blend weights and indices
  241.     hr = pMC->pSkinInfo->ConvertToIndexedBlendedMesh( pMC->MeshData.pMesh,
  242.         D3DXMESH_MANAGED | D3DXMESHOPT_VERTEXCACHE,
  243.         pMC->m_dwNumPaletteEntries,
  244.         pMC->pAdjacency,
  245.         NULL,
  246.         NULL,
  247.         NULL,
  248.         &pMC->m_dwMaxNumFaceInfls,
  249.         &pMC->m_dwNumAttrGroups,
  250.         &pMC->m_pBufBoneCombos,
  251.         &pMC->m_pWorkingMesh );
  252.     if( FAILED( hr ) )
  253.         goto e_Exit;
  254.  
  255.     // Make sure the working set is large enough for this mesh.
  256.     // This is a bone array used for all mesh containers as a working
  257.     // set during drawing.  If one was created previously that isn't 
  258.     // large enough for this mesh, we have to reallocate.
  259.     if( m_pMA->m_dwWorkingPaletteSize < pMC->m_dwNumPaletteEntries )
  260.     {
  261.         if( m_pMA->m_amxWorkingPalette )
  262.             delete [] m_pMA->m_amxWorkingPalette;
  263.  
  264.         m_pMA->m_dwWorkingPaletteSize = pMC->m_dwNumPaletteEntries;
  265.         m_pMA->m_amxWorkingPalette = new D3DXMATRIX[ m_pMA->m_dwWorkingPaletteSize ];
  266.         if( m_pMA->m_amxWorkingPalette == NULL )
  267.         {
  268.             m_pMA->m_dwWorkingPaletteSize = 0;
  269.             hr = E_OUTOFMEMORY;
  270.             goto e_Exit;
  271.         }
  272.     }
  273.  
  274.     // ensure the proper vertex format for the mesh
  275.     {
  276.         DWORD dwOldFVF = pMC->m_pWorkingMesh->GetFVF();
  277.         DWORD dwNewFVF = ( dwOldFVF & D3DFVF_POSITION_MASK ) | D3DFVF_NORMAL | D3DFVF_TEX1 | D3DFVF_LASTBETA_UBYTE4;
  278.         if( dwNewFVF != dwOldFVF )
  279.         {
  280.             LPD3DXMESH pMesh;
  281.             hr = pMC->m_pWorkingMesh->CloneMeshFVF( pMC->m_pWorkingMesh->GetOptions(),
  282.                 dwNewFVF,
  283.                 m_pMA->m_pDevice,
  284.                 &pMesh );
  285.             if( FAILED( hr ) )
  286.                 goto e_Exit;
  287.  
  288.             pMC->m_pWorkingMesh->Release();
  289.             pMC->m_pWorkingMesh = pMesh;
  290.  
  291.             // if the loaded mesh didn't contain normals, compute them here
  292.             if( ! ( dwOldFVF & D3DFVF_NORMAL ) )
  293.             {
  294.                 hr = D3DXComputeNormals( pMC->m_pWorkingMesh, NULL );
  295.                 if( FAILED( hr ) )
  296.                     goto e_Exit;
  297.             }
  298.         }
  299.     }
  300.  
  301.     // Interpret the UBYTE4 as a D3DCOLOR.
  302.     // The GeForce3 doesn't support the UBYTE4 decl type.  So, we convert any
  303.     // blend indices to a D3DCOLOR semantic, and later in the shader convert
  304.     // it back using the D3DCOLORtoUBYTE4() intrinsic.  Note that we don't
  305.     // convert any data, just the declaration.
  306.     D3DVERTEXELEMENT9 pDecl[ MAX_FVF_DECL_SIZE ];
  307.     D3DVERTEXELEMENT9 * pDeclCur;
  308.     hr = pMC->m_pWorkingMesh->GetDeclaration( pDecl );
  309.     if( FAILED( hr ) )
  310.         goto e_Exit;
  311.  
  312.     pDeclCur = pDecl;
  313.     while( pDeclCur->Stream != 0xff )
  314.     {
  315.         if( ( pDeclCur->Usage == D3DDECLUSAGE_BLENDINDICES ) && ( pDeclCur->UsageIndex == 0 ) )
  316.             pDeclCur->Type = D3DDECLTYPE_D3DCOLOR;
  317.         pDeclCur++;
  318.     }
  319.  
  320.     hr = pMC->m_pWorkingMesh->UpdateSemantics( pDecl );
  321.     if( FAILED( hr ) )
  322.         goto e_Exit;
  323.  
  324. e_Exit:
  325.  
  326.     if( FAILED( hr ) )
  327.     {
  328.         if( pMC )
  329.             DestroyMeshContainer( pMC );
  330.     }
  331.     else
  332.         * ppNewMeshContainer = pMC;
  333.  
  334.     return hr;
  335. }
  336.  
  337.  
  338.  
  339.  
  340. //-----------------------------------------------------------------------------
  341. // Name: CMultiAnimAllocateHierarchy::DestroyFrame()
  342. // Desc: Called by D3DX during the release of a mesh hierarchy.  Here we should
  343. //       free all resources allocated in CreateFrame().
  344. //-----------------------------------------------------------------------------
  345. HRESULT CMultiAnimAllocateHierarchy::DestroyFrame( THIS_ LPD3DXFRAME pFrameToFree )
  346. {
  347.     assert( m_pMA );
  348.  
  349.     MultiAnimFrame * pFrame = (MultiAnimFrame *) pFrameToFree;
  350.  
  351.     if( pFrame->Name )
  352.         delete [] pFrame->Name;
  353.  
  354.     delete pFrame;
  355.  
  356.     return S_OK;
  357. }
  358.  
  359.  
  360.  
  361.  
  362. //-----------------------------------------------------------------------------
  363. // Name: CMultiAnimAllocateHierarchy::DestroyMeshContainer()
  364. // Desc: Called by D3DX during the release of a mesh hierarchy.  Here we should
  365. //       free all resources allocated in CreateMeshContainer().
  366. //-----------------------------------------------------------------------------
  367. HRESULT CMultiAnimAllocateHierarchy::DestroyMeshContainer( THIS_ LPD3DXMESHCONTAINER pMeshContainerToFree )
  368. {
  369.     assert( m_pMA );
  370.  
  371.     MultiAnimMC * pMC = (MultiAnimMC *) pMeshContainerToFree;
  372.  
  373.     if( pMC->Name )
  374.         delete [] pMC->Name;
  375.  
  376.     if( pMC->MeshData.pMesh )
  377.         pMC->MeshData.pMesh->Release();
  378.  
  379.     if( pMC->pAdjacency )
  380.         delete [] pMC->pAdjacency;
  381.  
  382.     if( pMC->pMaterials )
  383.         delete [] pMC->pMaterials;
  384.  
  385.     for( DWORD i = 0; i < pMC->NumMaterials; ++ i )
  386.     {
  387.         if( pMC->m_apTextures[ i ] )
  388.             pMC->m_apTextures[ i ]->Release();
  389.     }
  390.  
  391.     if( pMC->m_apTextures )
  392.         delete [] pMC->m_apTextures;
  393.  
  394.     if( pMC->pSkinInfo )
  395.         pMC->pSkinInfo->Release();
  396.  
  397.     if( pMC->m_amxBoneOffsets )
  398.         delete [] pMC->m_amxBoneOffsets;
  399.  
  400.     if( pMC->m_pWorkingMesh )
  401.     {
  402.         pMC->m_pWorkingMesh->Release();
  403.         pMC->m_pWorkingMesh = NULL;
  404.     }
  405.  
  406.     pMC->m_dwNumPaletteEntries = 0;
  407.     pMC->m_dwMaxNumFaceInfls = 0;
  408.     pMC->m_dwNumAttrGroups = 0;
  409.  
  410.     if( pMC->m_pBufBoneCombos )
  411.     {
  412.         pMC->m_pBufBoneCombos->Release();
  413.         pMC->m_pBufBoneCombos = NULL;
  414.     }
  415.  
  416.     if( pMC->m_apmxBonePointers )
  417.         delete [] pMC->m_apmxBonePointers;
  418.  
  419.     delete pMeshContainerToFree;
  420.  
  421.     return S_OK;
  422. }
  423.